package fr.inserm.umr915.vcfserver.bio.samples;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.zip.GZIPInputStream;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamWriter;

import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import fr.inserm.umr915.vcfserver.bio.Segment;
import fr.inserm.umr915.vcfserver.bio.segparser.SegmentParser;

@SuppressWarnings("serial")
public class SampleServlet extends HttpServlet
	{
	private List<Sample> samples=null;
	@SuppressWarnings("unchecked")
	@Override
	public void init(ServletConfig config) throws ServletException {
		super.init(config);
		WebApplicationContext factory = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
		
		if(factory.containsBean("samples"))
			{
			samples=new ArrayList<Sample>((List<Sample>)factory.getBean("samples"));
			}
		else
			{
			samples=Collections.emptyList();
			}
		this.samples=Collections.unmodifiableList(this.samples);
		}
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException
		{
		doGet(req, resp);
		}
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException
		{
		String sampleName=req.getParameter("sample");
		Sample sample=null;
		if(sampleName!=null)
			{
			for(Sample sa: this.samples)
				{
				if(sampleName.equals(sa.getName()))
					{
					sample=sa;
					break;
					}
				}
			}
		/* ============== EXPORT VCF ==========================================*/
		String vcfName= req.getParameter("vcf");
		if(vcfName!=null)
			{
			if(sample==null) throw new ServletException("@sample undefined");
			File vcfFile=null;
			for(File v:sample.getVcfs())
				{
				if(v.toString().equals(vcfName))
					{
					vcfFile=v;
					break;
					}
				}
			if(vcfFile==null) throw new FileNotFoundException(vcfName);
			if(!vcfFile.isFile()) throw new IOException("Not a file "+vcfName);
			if(!vcfFile.canRead()) throw new IOException("cannot read file "+vcfName);
			
			PrintWriter out=null;
			BufferedReader in=null;
			try {
				String encoding=resp.getCharacterEncoding();
				if(encoding==null)
					{
					encoding="UTF-8";
					resp.setCharacterEncoding(encoding);
					}
				out=resp.getWriter();
				if(vcfFile.getName().toLowerCase().endsWith(".gz"))
					{
					in=new BufferedReader(new InputStreamReader(new GZIPInputStream(new FileInputStream(vcfFile)), encoding));
					}
				else
					{
					in=new BufferedReader(new FileReader(vcfFile));
					}
				resp.setContentType("text/plain");
				char buff[]=new char[2048];
				int nRead=0;
				while((nRead=in.read(buff))!=-1)
					{
					out.write(buff, 0, nRead);
					}
				return;
				} 
			catch (IOException e)
				{
				throw e;
				}
			finally
				{
				if(out!=null) out.flush();
				if(out!=null) out.close();
				if(in!=null) in.close();
				}
			}
		
		/* ============== SHOW BAM ==========================================*/
		String segment= req.getParameter("segment");
		if(segment!=null)
			{
			if(sample==null) throw new ServletException("@sample undefined");
			if(sample.getBamFile()==null) throw new ServletException("no bam for "+sampleName);
			Segment seg=null;
			try {
				seg=SegmentParser.parseOne(segment);
				} 
			catch (Exception e) {
				throw new ServletException(e);
				}
			req.setAttribute("segment", seg);
			req.setAttribute("sample", sample);
			req.getRequestDispatcher("/showbam").forward(req, resp);
			return;
			}
		
		//http://www.cs.waikato.ac.nz/~ml/weka/arff.html
		if(req.getServletPath().endsWith(".txt"))
			{
			resp.setContentType("text/plain");
			PrintWriter w=resp.getWriter();
			for(Sample sa:this.samples)
				{
				for(File v: sa.getVcfs())
					{
					w.print(sa.getName());
					w.print("\t");
					w.print(v.toString());
					w.print("\t");
					if(sa.getBamFile()!=null)
						{
						w.print(sa.getBamFile().toString());
						}
					w.println();
					}
				}
			w.flush();
			w.close();
			return;
			}
		
		//http://www.cs.waikato.ac.nz/~ml/weka/arff.html
		if(req.getServletPath().endsWith(".arff"))
			{
			resp.setContentType("text/plain");
			PrintWriter w=resp.getWriter();
			w.println("@RELATION samples");
			w.println("@ATTRIBUTE SAMPLE string");
			w.println("@ATTRIBUTE vcf string");
			w.println("@ATTRIBUTE bam string");
			w.println("@DATA");
			for(Sample sa:this.samples)
				{
				for(File v: sa.getVcfs())
					{
					w.print("\"");
					w.print(sa.getName());
					w.print("\",\"");
					w.print(v.toString());
					w.print("\",");
					if(sa.getBamFile()!=null)
						{
						w.print("\"");
						w.print(sa.getBamFile().toString());
						w.print("\"");
						}
					else
						{
						w.print("?");
						}
					w.println();
					}
				}
			w.flush();
			w.close();
			return;
			}
		
		/* ============== DUMP XML ==========================================*/
		OutputStream out=null;
		try
			{
			String encoding=resp.getCharacterEncoding();
			if(encoding==null) encoding="UTF-8";
			resp.setContentType("text/xml");
			out=resp.getOutputStream();
			XMLOutputFactory xmlfactory= XMLOutputFactory.newInstance();
			XMLStreamWriter w= xmlfactory.createXMLStreamWriter(out,encoding);
			w.writeStartDocument(encoding,"1.0");
			w.writeStartElement("SampleList");
			for(Sample sa:this.samples)
				{
				w.writeStartElement("Sample");
					w.writeStartElement("name");
					w.writeCharacters(sa.getName());
					w.writeEndElement();
					w.writeStartElement("description");
					w.writeCharacters(sa.getDescription());
					w.writeEndElement();
					w.writeStartElement("bam");
					w.writeCharacters(sa.getBamFile().toString());
					w.writeEndElement();
					for(File v:sa.getVcfs())
						{
						w.writeStartElement("vcf");
						w.writeCharacters(v.toString());
						w.writeEndElement();
						}
				w.writeEndElement();
				}
			w.writeEndElement();
			w.writeEndDocument();
			w.flush();
			}
		catch(Exception e)
			{
			throw new ServletException(e);
			}
		finally
			{
			if(out!=null) out.flush();
			if(out!=null) out.close();
			}
		}
}
